package upload

import (
	"bytes"
	"crypto/md5"
	"crypto/sha256"
	"encoding/hex"
	"io"
	"io/ioutil"
	"strings"
)

type uploadInterface interface {
	SetKey(ak string, as string)
	SetBucket(bucket string)
	Upload(File) (FormData, error)
}

type File interface {
	GetFileName() string
	GetExt() string
	GetMd5Hash() string
	GetTitle() string
	GetOption() option

	SetTitle(string)

	getFileName() string
	getPath() string
	getReader() io.Reader
	getSize() int64
}

func NewFile(fileName string, size int64, render io.Reader, option ...fileOption) File {
	file := &file{
		fileName: fileName,
		size:     size,
	}

	for _, v := range option {
		v.apply(file)
	}

	fn, _ := ioutil.ReadAll(render)
	s256 := sha256.New()
	s256.Write(fn)
	md := md5.New()
	io.Copy(md, strings.NewReader(hex.EncodeToString(s256.Sum(nil))))
	file.hash = hex.EncodeToString(md.Sum(nil))
	file.reader = bytes.NewReader(fn)
	return file
}

type option struct {
	FileName string
	MineType string
}

type file struct {
	title     string
	fileName  string
	size      int64
	reader    io.Reader
	nFileName string
	Path      string
	Param     map[string]string
	hash      string
	option    option
}

func (n *file) SetTitle(url string) {
	n.title = url
}

func (n *file) GetFileName() string {
	return n.fileName
}

func (n *file) GetExt() string {
	index := strings.LastIndex(n.nFileName, ".")
	return n.nFileName[index+1:]
}

func (n *file) GetMd5Hash() string {
	return n.hash
}

func (n *file) GetTitle() string {
	return n.title
}

func (n *file) GetOption() option {
	return n.option
}

func (n *file) getFileName() string {
	if n.nFileName == "" {
		s256 := sha256.New()
		s256.Write([]byte(n.fileName))
		n.nFileName = hex.EncodeToString(s256.Sum(nil)) + "." + n.fileName[strings.LastIndex(n.fileName, ".")+1:]
	}
	return n.nFileName
}

func (n *file) getPath() string {
	return n.Path
}

func (n *file) getReader() io.Reader {
	return n.reader
}

func (n *file) getSize() int64 {
	return n.size
}
